package models

import (
	"context"
	"errors"
	"time"
)

// 错误定义
var (
	ErrInsufficientBalance = errors.New("红包余额不足")
	ErrRecordNotFound      = errors.New("记录不存在")
	ErrRecordStatusInvalid = errors.New("记录状态无效")
)

// RedPacketAccount 红包账户表
type RedPacketAccount struct {
	Id           int64     `json:"id" xorm:"pk autoincr"`
	UserId       int64     `json:"user_id" xorm:"not null comment('用户ID') unique"`
	Balance      float64   `json:"balance" xorm:"decimal(10,2) not null default 0 comment('红包余额')"`
	TotalIncome  float64   `json:"total_income" xorm:"decimal(10,2) not null default 0 comment('累计收入')"`
	TotalExpense float64   `json:"total_expense" xorm:"decimal(10,2) not null default 0 comment('累计支出')"`
	UpdateTime   time.Time `json:"update_time" xorm:"not null updated comment('更新时间')"`
	CreateTime   time.Time `json:"create_time" xorm:"not null created comment('创建时间')"`
}

// TableName 表名
func (RedPacketAccount) TableName() string {
	return "red_packet_account"
}

// GetRedPacketAccount 获取用户红包账户
func GetRedPacketAccount(ctx context.Context, userId int64) (*RedPacketAccount, error) {
	var account RedPacketAccount
	exists, err := Get(ctx, &account, "user_id = ?", userId)
	if err != nil {
		return nil, err
	}
	if !exists {
		// 账户不存在则创建
		account = RedPacketAccount{
			UserId:       userId,
			Balance:      0,
			TotalIncome:  0,
			TotalExpense: 0,
		}
		_, err = Insert(ctx, &account)
		if err != nil {
			return nil, err
		}
	}
	return &account, nil
}

// UpdateBalance 更新账户余额
func (a *RedPacketAccount) UpdateBalance(ctx context.Context, amount float64, isIncome bool) error {
	session := getSession(ctx)
	defer session.Close()

	// 开启事务
	if err := session.Begin(); err != nil {
		return err
	}

	// 更新余额
	if isIncome {
		a.Balance += amount
		a.TotalIncome += amount
	} else {
		a.Balance -= amount
		a.TotalExpense += amount
	}

	// 检查余额是否充足
	if a.Balance < 0 {
		session.Rollback()
		return ErrInsufficientBalance
	}

	// 更新账户
	if _, err := session.ID(a.Id).Update(a); err != nil {
		session.Rollback()
		return err
	}

	return session.Commit()
}
